package com.atguigu.gulimall.order.config;

import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRabbitConfig {

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 定制 RabbitTemplate
     *
     * @PostConstruct： MyRabbitConfig创建完成之后，执行方法
     *
     * 发送端确认机制
     * publisher-confirms: true
     * publisher-returns: true
     *
     *
     * 消费端确认机制
     *      默认是收到消息，自动确认 rabbit.listener.simple.acknowledge-mode: auto
     *      （问题，收到很多消息，都自动回复给rabbit了，但是只有1个消息处理成功，然后宕机了，消息丢失）
     * 解决办法，手动确认机制 rabbit.listener.simple.acknowledge-mode: manual
     *      只要没有明确告诉MQ，消息被消费，消息就一直是noack状态，即使消费端，消息不会丢失，会自动变成ready状态
     */
    @Bean RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        /**
         # 开启发送端确认：消息抵达rabbit服务器(broker)
         publisher-confirms: true
         * ConfirmCallback 只要消息抵达rabbit服务器，ack回调就为true
         *
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            /**
             * correlationData 唯一的消息关联数据：（消息的唯一ID）
             * ack 消息是否成功收到
             * cause 失败原因
             */
            // 将每个发送的消息都在数据库做好记录，定期将失败的消息，重新发送一遍
        });

        /**
         *     # 开启发送端确认：消息抵达queue队列
         *     publisher-returns: true
         *     # 只要消息抵达队列，以异步发送优先回调 returnConfirm
         *     template:
         *       mandatory: true
         *  ReturnCallback 消息投递给队列失败时，回调的方法
         */
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            /**
             * message 投递失败的消息详细信息
             * replyCode 回复的状态码
             * replyText 回复的文本内容
             * exchange 当时这个消息发给哪个交换机
             * routingKey 当时这个消息用哪个路由键
             */
            System.out.println("失败的消息：message[" + message+"]，replyCode["+replyCode+"]，replyText["+replyText+"]，exchange["+exchange+"]，routingKey["+routingKey+"]");
        });
        return rabbitTemplate;
    }

}
